[XEN] Simplify VMCS allocation (never bigger than a page).
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Mon, 25 Sep 2006 16:46:08 +0000 (17:46 +0100)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Mon, 25 Sep 2006 16:46:08 +0000 (17:46 +0100)
Dynamically determine reserved bits in execution-control
fields.
Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/hvm/vmx/vmcs.c
xen/arch/x86/hvm/vmx/vmx.c
xen/include/asm-x86/hvm/vmx/vmcs.h
xen/include/asm-x86/hvm/vmx/vmx.h

index 5c80d7e89a296a52000dfd42412d27c47cfc6358..3892ffa1c3ee69495cb804df7e824c1e6e7a058f 100644 (file)
 #include <xen/keyhandler.h>
 #include <asm/shadow.h>
 
-static int vmcs_size;
-static int vmcs_order;
+/* Basic flags for Pin-based VM-execution controls. */
+#define MONITOR_PIN_BASED_EXEC_CONTROLS                 \
+    ( PIN_BASED_EXT_INTR_MASK |                         \
+      PIN_BASED_NMI_EXITING )
+
+/* Basic flags for CPU-based VM-execution controls. */
+#ifdef __x86_64__
+#define MONITOR_CPU_BASED_EXEC_CONTROLS_SUBARCH         \
+    ( CPU_BASED_CR8_LOAD_EXITING |                      \
+      CPU_BASED_CR8_STORE_EXITING )
+#else
+#define MONITOR_CPU_BASED_EXEC_CONTROLS_SUBARCH 0
+#endif
+#define MONITOR_CPU_BASED_EXEC_CONTROLS                 \
+    ( MONITOR_CPU_BASED_EXEC_CONTROLS_SUBARCH |         \
+      CPU_BASED_HLT_EXITING |                           \
+      CPU_BASED_INVDPG_EXITING |                        \
+      CPU_BASED_MWAIT_EXITING |                         \
+      CPU_BASED_MOV_DR_EXITING |                        \
+      CPU_BASED_ACTIVATE_IO_BITMAP |                    \
+      CPU_BASED_USE_TSC_OFFSETING )
+
+/* Basic flags for VM-Exit controls. */
+#ifdef __x86_64__
+#define MONITOR_VM_EXIT_CONTROLS_SUBARCH VM_EXIT_IA32E_MODE
+#else
+#define MONITOR_VM_EXIT_CONTROLS_SUBARCH 0
+#endif
+#define MONITOR_VM_EXIT_CONTROLS                        \
+    ( MONITOR_VM_EXIT_CONTROLS_SUBARCH |                \
+      VM_EXIT_ACK_INTR_ON_EXIT )
+
+/* Basic flags for VM-Entry controls. */
+#define MONITOR_VM_ENTRY_CONTROLS                       0x00000000
+
+/* Dynamic (run-time adjusted) execution control flags. */
+static u32 vmx_pin_based_exec_control;
+static u32 vmx_cpu_based_exec_control;
+static u32 vmx_vmexit_control;
+static u32 vmx_vmentry_control;
+
 static u32 vmcs_revision_id;
 
-void vmx_init_vmcs_config(void)
+static u32 adjust_vmx_controls(u32 ctrls, u32 msr)
 {
     u32 vmx_msr_low, vmx_msr_high;
 
-    if ( vmcs_size )
-        return;
+    rdmsr(msr, vmx_msr_low, vmx_msr_high);
+
+    /* Bit == 0 means must be zero. */
+    BUG_ON(ctrls & ~vmx_msr_high);
+
+    /* Bit == 1 means must be one. */
+    ctrls |= vmx_msr_low;
+
+    return ctrls;
+}
+
+void vmx_init_vmcs_config(void)
+{
+    u32 vmx_msr_low, vmx_msr_high;
+    u32 _vmx_pin_based_exec_control;
+    u32 _vmx_cpu_based_exec_control;
+    u32 _vmx_vmexit_control;
+    u32 _vmx_vmentry_control;
+
+    _vmx_pin_based_exec_control =
+        adjust_vmx_controls(MONITOR_PIN_BASED_EXEC_CONTROLS,
+                            MSR_IA32_VMX_PINBASED_CTLS_MSR);
+    _vmx_cpu_based_exec_control =
+        adjust_vmx_controls(MONITOR_CPU_BASED_EXEC_CONTROLS,
+                            MSR_IA32_VMX_PROCBASED_CTLS_MSR);
+    _vmx_vmexit_control =
+        adjust_vmx_controls(MONITOR_VM_EXIT_CONTROLS,
+                            MSR_IA32_VMX_EXIT_CTLS_MSR);
+    _vmx_vmentry_control =
+        adjust_vmx_controls(MONITOR_VM_ENTRY_CONTROLS,
+                            MSR_IA32_VMX_ENTRY_CTLS_MSR);
 
     rdmsr(MSR_IA32_VMX_BASIC_MSR, vmx_msr_low, vmx_msr_high);
 
-    vmcs_revision_id = vmx_msr_low;
+    if ( smp_processor_id() == 0 )
+    {
+        vmcs_revision_id = vmx_msr_low;
+        vmx_pin_based_exec_control = _vmx_pin_based_exec_control;
+        vmx_cpu_based_exec_control = _vmx_cpu_based_exec_control;
+        vmx_vmexit_control         = _vmx_vmexit_control;
+        vmx_vmentry_control        = _vmx_vmentry_control;
+    }
+    else
+    {
+        BUG_ON(vmcs_revision_id != vmx_msr_low);
+        BUG_ON(vmx_pin_based_exec_control != _vmx_pin_based_exec_control);
+        BUG_ON(vmx_cpu_based_exec_control != _vmx_cpu_based_exec_control);
+        BUG_ON(vmx_vmexit_control != _vmx_vmexit_control);
+        BUG_ON(vmx_vmentry_control != _vmx_vmentry_control);
+    }
 
-    vmcs_size  = vmx_msr_high & 0x1fff;
-    vmcs_order = get_order_from_bytes(vmcs_size);
+    /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */
+    BUG_ON((vmx_msr_high & 0x1fff) > PAGE_SIZE);
 }
 
 static struct vmcs_struct *vmx_alloc_vmcs(void)
 {
     struct vmcs_struct *vmcs;
 
-    if ( (vmcs = alloc_xenheap_pages(vmcs_order)) == NULL )
+    if ( (vmcs = alloc_xenheap_page()) == NULL )
     {
         DPRINTK("Failed to allocate VMCS.\n");
         return NULL;
     }
 
-    memset(vmcs, 0, vmcs_size); /* don't remove this */
+    memset(vmcs, 0, PAGE_SIZE);
     vmcs->vmcs_revision_id = vmcs_revision_id;
 
     return vmcs;
@@ -74,7 +157,7 @@ static struct vmcs_struct *vmx_alloc_vmcs(void)
 
 static void vmx_free_vmcs(struct vmcs_struct *vmcs)
 {
-    free_xenheap_pages(vmcs, vmcs_order);
+    free_xenheap_page(vmcs);
 }
 
 static void __vmx_clear_vmcs(void *info)
@@ -156,12 +239,11 @@ static inline int construct_vmcs_controls(struct arch_vmx_struct *arch_vmx)
 {
     int error = 0;
 
-    error |= __vmwrite(PIN_BASED_VM_EXEC_CONTROL,
-                       MONITOR_PIN_BASED_EXEC_CONTROLS);
+    error |= __vmwrite(PIN_BASED_VM_EXEC_CONTROL, vmx_pin_based_exec_control);
 
-    error |= __vmwrite(VM_EXIT_CONTROLS, MONITOR_VM_EXIT_CONTROLS);
+    error |= __vmwrite(VM_EXIT_CONTROLS, vmx_vmexit_control);
 
-    error |= __vmwrite(VM_ENTRY_CONTROLS, MONITOR_VM_ENTRY_CONTROLS);
+    error |= __vmwrite(VM_ENTRY_CONTROLS, vmx_vmentry_control);
 
     error |= __vmwrite(IO_BITMAP_A, virt_to_maddr(arch_vmx->io_bitmap_a));
     error |= __vmwrite(IO_BITMAP_B, virt_to_maddr(arch_vmx->io_bitmap_b));
@@ -246,9 +328,8 @@ static void vmx_do_launch(struct vcpu *v)
     error |= __vmwrite(GUEST_CR0, cr0);
     cr0 &= ~X86_CR0_PG;
     error |= __vmwrite(CR0_READ_SHADOW, cr0);
-    error |= __vmwrite(CPU_BASED_VM_EXEC_CONTROL,
-                       MONITOR_CPU_BASED_EXEC_CONTROLS);
-    v->arch.hvm_vcpu.u.vmx.exec_control = MONITOR_CPU_BASED_EXEC_CONTROLS;
+    error |= __vmwrite(CPU_BASED_VM_EXEC_CONTROL, vmx_cpu_based_exec_control);
+    v->arch.hvm_vcpu.u.vmx.exec_control = vmx_cpu_based_exec_control;
 
     __asm__ __volatile__ ("mov %%cr4,%0" : "=r" (cr4) : );
 
@@ -297,22 +378,22 @@ static inline int construct_init_vmcs_guest(cpu_user_regs_t *regs)
     /* MSR */
     error |= __vmwrite(VM_EXIT_MSR_LOAD_ADDR, 0);
     error |= __vmwrite(VM_EXIT_MSR_STORE_ADDR, 0);
-
     error |= __vmwrite(VM_EXIT_MSR_STORE_COUNT, 0);
     error |= __vmwrite(VM_EXIT_MSR_LOAD_COUNT, 0);
     error |= __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0);
-    /* interrupt */
+
     error |= __vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0);
-    /* mask */
-    error |= __vmwrite(CR0_GUEST_HOST_MASK, -1UL);
-    error |= __vmwrite(CR4_GUEST_HOST_MASK, -1UL);
+
+    error |= __vmwrite(CR0_GUEST_HOST_MASK, ~0UL);
+    error |= __vmwrite(CR4_GUEST_HOST_MASK, ~0UL);
 
     error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0);
     error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, 0);
 
-    /* TSC */
     error |= __vmwrite(CR3_TARGET_COUNT, 0);
 
+    error |= __vmwrite(GUEST_ACTIVITY_STATE, 0);
+
     /* Guest Selectors */
     error |= __vmwrite(GUEST_ES_SELECTOR, GUEST_LAUNCH_DS);
     error |= __vmwrite(GUEST_SS_SELECTOR, GUEST_LAUNCH_DS);
index cda90bc76da6f4338cd0a3da3ee4e3c4a48df7cc..89f22352a0e0f591c1d75d1f8762b98329dbbce6 100644 (file)
@@ -684,21 +684,6 @@ static void vmx_init_ap_context(struct vcpu_guest_context *ctxt,
 
 void do_nmi(struct cpu_user_regs *);
 
-static int check_vmx_controls(u32 ctrls, u32 msr)
-{
-    u32 vmx_msr_low, vmx_msr_high;
-
-    rdmsr(msr, vmx_msr_low, vmx_msr_high);
-    if ( (ctrls < vmx_msr_low) || (ctrls > vmx_msr_high) )
-    {
-        printk("Insufficient VMX capability 0x%x, "
-               "msr=0x%x,low=0x%8x,high=0x%x\n",
-               ctrls, msr, vmx_msr_low, vmx_msr_high);
-        return 0;
-    }
-    return 1;
-}
-
 static void vmx_init_hypercall_page(struct domain *d, void *hypercall_page)
 {
     char *p;
@@ -791,7 +776,7 @@ int start_vmx(void)
      */
     boot_cpu_data.x86_capability[4] = cpuid_ecx(1);
 
-    if (!(test_bit(X86_FEATURE_VMXE, &boot_cpu_data.x86_capability)))
+    if ( !test_bit(X86_FEATURE_VMXE, &boot_cpu_data.x86_capability) )
         return 0;
 
     rdmsr(IA32_FEATURE_CONTROL_MSR, eax, edx);
@@ -811,24 +796,11 @@ int start_vmx(void)
               IA32_FEATURE_CONTROL_MSR_ENABLE_VMXON, 0);
     }
 
-    if ( !check_vmx_controls(MONITOR_PIN_BASED_EXEC_CONTROLS,
-                             MSR_IA32_VMX_PINBASED_CTLS_MSR) )
-        return 0;
-    if ( !check_vmx_controls(MONITOR_CPU_BASED_EXEC_CONTROLS,
-                             MSR_IA32_VMX_PROCBASED_CTLS_MSR) )
-        return 0;
-    if ( !check_vmx_controls(MONITOR_VM_EXIT_CONTROLS,
-                             MSR_IA32_VMX_EXIT_CTLS_MSR) )
-        return 0;
-    if ( !check_vmx_controls(MONITOR_VM_ENTRY_CONTROLS,
-                             MSR_IA32_VMX_ENTRY_CTLS_MSR) )
-        return 0;
-
     set_in_cr4(X86_CR4_VMXE);
 
     vmx_init_vmcs_config();
-    
-    if(!smp_processor_id())
+
+    if ( smp_processor_id() == 0 )
         setup_vmcs_dump();
 
     if ( (vmcs = vmx_alloc_host_vmcs()) == NULL )
@@ -1519,7 +1491,7 @@ static int vmx_set_cr0(unsigned long value)
                     &v->arch.hvm_vmx.cpu_state);
 
             __vmread(VM_ENTRY_CONTROLS, &vm_entry_value);
-            vm_entry_value |= VM_ENTRY_CONTROLS_IA32E_MODE;
+            vm_entry_value |= VM_ENTRY_IA32E_MODE;
             __vmwrite(VM_ENTRY_CONTROLS, vm_entry_value);
         }
 #endif
@@ -1573,7 +1545,7 @@ static int vmx_set_cr0(unsigned long value)
                 clear_bit(VMX_CPU_STATE_LMA_ENABLED,
                           &v->arch.hvm_vmx.cpu_state);
                 __vmread(VM_ENTRY_CONTROLS, &vm_entry_value);
-                vm_entry_value &= ~VM_ENTRY_CONTROLS_IA32E_MODE;
+                vm_entry_value &= ~VM_ENTRY_IA32E_MODE;
                 __vmwrite(VM_ENTRY_CONTROLS, vm_entry_value);
             }
         }
@@ -2296,15 +2268,8 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs)
         domain_crash_synchronous();
         break;
     case EXIT_REASON_PENDING_INTERRUPT:
-        /*
-         * Not sure exactly what the purpose of this is.  The only bits set
-         * and cleared at this point are CPU_BASED_VIRTUAL_INTR_PENDING.
-         * (in io.c:{enable,disable}_irq_window().  So presumably we want to
-         * set it to the original value...
-         */
+        /* Disable the interrupt window. */
         v->arch.hvm_vcpu.u.vmx.exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
-        v->arch.hvm_vcpu.u.vmx.exec_control |=
-            (MONITOR_CPU_BASED_EXEC_CONTROLS & CPU_BASED_VIRTUAL_INTR_PENDING);
         __vmwrite(CPU_BASED_VM_EXEC_CONTROL,
                   v->arch.hvm_vcpu.u.vmx.exec_control);
         break;
index 02097010c1585f214a621f1c5ccd87c8189976e4..ef40261a00c9f141236779f9a2ef718cd651dbb6 100644 (file)
@@ -132,12 +132,16 @@ extern int vmcs_version;
 #define CPU_BASED_ACTIVATE_IO_BITMAP    0x02000000
 #define CPU_BASED_MONITOR_EXITING       0x20000000
 #define CPU_BASED_PAUSE_EXITING         0x40000000
-#define PIN_BASED_EXT_INTR_MASK 0x1
-#define PIN_BASED_NMI_EXITING   0x8
 
+#define PIN_BASED_EXT_INTR_MASK         0x00000001
+#define PIN_BASED_NMI_EXITING           0x00000008
+
+#define VM_EXIT_IA32E_MODE              0x00000200
 #define VM_EXIT_ACK_INTR_ON_EXIT        0x00008000
-#define VM_EXIT_HOST_ADD_SPACE_SIZE     0x00000200
 
+#define VM_ENTRY_IA32E_MODE             0x00000200
+#define VM_ENTRY_SMM                    0x00000400
+#define VM_ENTRY_DEACT_DUAL_MONITOR     0x00000800
 
 /* VMCS Encordings */
 enum vmcs_field {
@@ -217,6 +221,7 @@ enum vmcs_field {
     GUEST_LDTR_AR_BYTES             = 0x00004820,
     GUEST_TR_AR_BYTES               = 0x00004822,
     GUEST_INTERRUPTIBILITY_INFO     = 0x00004824,
+    GUEST_ACTIVITY_STATE            = 0x00004826,
     GUEST_SYSENTER_CS               = 0x0000482A,
     HOST_IA32_SYSENTER_CS           = 0x00004c00,
     CR0_GUEST_HOST_MASK             = 0x00006000,
index fadb551e7c972dacc42126b332ec9cde702bca97..5750f0ca3fe266701c4e8e3f48d2bf811840ea28 100644 (file)
@@ -36,73 +36,6 @@ extern void set_guest_time(struct vcpu *v, u64 gtime);
 
 extern unsigned int cpu_rev;
 
-/*
- * Need fill bits for SENTER
- */
-
-#define MONITOR_PIN_BASED_EXEC_CONTROLS_RESERVED_VALUE  0x00000016
-
-#define MONITOR_PIN_BASED_EXEC_CONTROLS                 \
-    (                                                   \
-    MONITOR_PIN_BASED_EXEC_CONTROLS_RESERVED_VALUE |    \
-    PIN_BASED_EXT_INTR_MASK |                           \
-    PIN_BASED_NMI_EXITING                               \
-    )
-
-#define MONITOR_CPU_BASED_EXEC_CONTROLS_RESERVED_VALUE  0x0401e172
-
-#define _MONITOR_CPU_BASED_EXEC_CONTROLS                \
-    (                                                   \
-    MONITOR_CPU_BASED_EXEC_CONTROLS_RESERVED_VALUE |    \
-    CPU_BASED_HLT_EXITING |                             \
-    CPU_BASED_INVDPG_EXITING |                          \
-    CPU_BASED_MWAIT_EXITING |                           \
-    CPU_BASED_MOV_DR_EXITING |                          \
-    CPU_BASED_ACTIVATE_IO_BITMAP |                      \
-    CPU_BASED_USE_TSC_OFFSETING                         \
-    )
-
-#define MONITOR_CPU_BASED_EXEC_CONTROLS_IA32E_MODE      \
-    (                                                   \
-    CPU_BASED_CR8_LOAD_EXITING |                        \
-    CPU_BASED_CR8_STORE_EXITING                         \
-    )
-
-#define MONITOR_VM_EXIT_CONTROLS_RESERVED_VALUE         0x0003edff
-
-#define MONITOR_VM_EXIT_CONTROLS_IA32E_MODE             0x00000200
-
-#define _MONITOR_VM_EXIT_CONTROLS                       \
-    (                                                   \
-    MONITOR_VM_EXIT_CONTROLS_RESERVED_VALUE |           \
-    VM_EXIT_ACK_INTR_ON_EXIT                            \
-    )
-
-#if defined (__x86_64__)
-#define MONITOR_CPU_BASED_EXEC_CONTROLS                 \
-    (                                                   \
-    _MONITOR_CPU_BASED_EXEC_CONTROLS |                  \
-    MONITOR_CPU_BASED_EXEC_CONTROLS_IA32E_MODE          \
-    )
-#define MONITOR_VM_EXIT_CONTROLS                        \
-    (                                                   \
-    _MONITOR_VM_EXIT_CONTROLS |                         \
-    MONITOR_VM_EXIT_CONTROLS_IA32E_MODE                 \
-    )
-#else
-#define MONITOR_CPU_BASED_EXEC_CONTROLS                 \
-    _MONITOR_CPU_BASED_EXEC_CONTROLS
-
-#define MONITOR_VM_EXIT_CONTROLS                        \
-    _MONITOR_VM_EXIT_CONTROLS
-#endif
-
-#define VM_ENTRY_CONTROLS_RESERVED_VALUE                0x000011ff
-#define VM_ENTRY_CONTROLS_IA32E_MODE                    0x00000200
-
-#define MONITOR_VM_ENTRY_CONTROLS                       \
-    VM_ENTRY_CONTROLS_RESERVED_VALUE
-
 /*
  * Exit Reasons
  */